
"""
define "Person" entity
"""

import unittest
import cPickle
import struct

import serialize_helper

class Person(object):

    RACE_YELLOW = 0
    RACE_WHITE = 1
    RACE_BLACK = 2
    
    def __init__(self,ssn,name):
        self._ssn = ssn
        self._name = name
        
    def __eq__(self,rhs):
        if self is rhs:
            return True
        elif isinstance(rhs,Person):
            return (self._ssn == rhs._ssn) and (self._name == rhs._name)
        else:
            return False
        
    def __ne__(self,rhs):
        return not self == rhs

    def __str__(self):
        return "Person<%d,%s>"%(self._ssn,self._name)
        
class StructPackSerializer(object):
    
    SSN_FORMAT = "=I"
    SSN_SIZE = struct.calcsize(SSN_FORMAT) 
    
    def serialize(person):
        binimage = struct.pack(StructPackSerializer.SSN_FORMAT,person._ssn)
        binimage += serialize_helper.pack_string(person._name) 
        return binimage
    serialize = staticmethod(serialize)
    
    def deserialize(binimage):
        aperson = Person(0,None)
        
        offset = 0
        aperson._ssn, = struct.unpack(StructPackSerializer.SSN_FORMAT,binimage[offset : offset + StructPackSerializer.SSN_SIZE])
        
        offset += StructPackSerializer.SSN_SIZE
        aperson._name,offset = serialize_helper.unpack_string(binimage,offset)
        
        return aperson
    deserialize = staticmethod(deserialize)
        
# **************************************************************************** #
# test case
# **************************************************************************** #
class TestPerson(unittest.TestCase):
    def test_equal(self):
        person1 = Person(1,"cheka")
        person2 = Person(1,"cheka")
        
        self.assertEqual(person1,person1)
        
        self.assertTrue(person1 is not person2)
        self.assertEqual(person1,person2)
        
        person2._name = "new name"
        self.assertNotEqual(person1,person2)
        
    def test_list_equal(self):
        """
        since Person class itself has override "equal" operation
        a collection of person will automatically check equality with its peer based on content other than reference
        """
        list1 = [Person(1,"cheka"),Person(2,"stasi")]
        list2 = [Person(1,"cheka"),Person(2,"stasi")]
        self.assertEqual(list1,list2)
        
    def test_dict_equal(self):
        infos = ((1,"cheka"),(2,"stasi"))
        
        dict1 = {}
        dict2 = {}
        for atuple in infos:
            dict1[atuple[0]] = Person(atuple[0],atuple[1])
            dict2[atuple[0]] = Person(atuple[0],atuple[1])
            
        # ------------ check
        for atuple in infos:
            ssn = atuple[0]
            self.assertTrue(dict1[ssn] is not dict2[ssn])
        self.assertEqual(dict1,dict2)
        
    def test_to_string(self):
        aperson = Person(1,"cheka")
        self.assertEqual("Person<1,cheka>",str(aperson))
        
        
if __name__ == "__main__":
    unittest.main()